package com.wpml;

import cn.hutool.core.util.ArrayUtil;
import com.wpml.annotation.Bean;
import com.wpml.annotation.Controller;
import com.wpml.annotation.Param;
import com.wpml.annotation.RequestMapping;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

/**
 * @Description
 * @Date 2021-08-19
 * @Author wangpei
 **/
public class BeanFactory {

    private static final Map<String, BeanMateData> beanContainer = new HashMap<>();
    private static final List<Class<?>> beanList = new ArrayList<>();
    static Properties properties;

    static Properties globalProperties;

    static {
        try {

            properties = loadProperties("mvc.properties");
            globalProperties = loadProperties("scanPackagePath.properties");

            loadBeanDefinition();
            System.out.println("初始化加载类信息完成...");

            init("");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("系统资源加载失败");
            System.exit(-1);
        }
    }

    private static Properties loadProperties(String filePath) throws IOException {
        InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream(filePath);
        Properties properties = new Properties();
        properties.load(is);
        return properties;
    }

    /**
     * 从指定路径下扫描Bean注解标识的类
     * @return 返回Class集合
     */
    public static void loadBeanDefinition() throws Exception {
        // 获取根路径
        ClassLoader classLoader = BeanFactory.class.getClassLoader();
        URL rootUrl = classLoader.getResource("scanPackagePath.properties");

        assert rootUrl != null;
        String rootPath = rootUrl.toString();
        String realPath = rootPath.substring("file:/".length(), rootPath.lastIndexOf("/")).replace("/", File.separator);

        String classPath = realPath; // 类根路径

        String poPkg = globalProperties.getProperty("scan.po.path");

        realPath = realPath + File.separator + poPkg.replace(".", File.separator);

        File file = new File(realPath);
        File[] files = file.listFiles();
        List<File> listFile = new ArrayList<>();
        recursiveLoadClassFile(files, listFile);

        // 获取类加载器
//        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{rootUrl});


        for (File classFile : listFile) {
            String className = classFile.getPath().substring(classPath.length() + 1, classFile.getPath().length() - 6);

            Class<?> clazz = classLoader.loadClass(className.replace(File.separator, "."));
            Bean[] annotationsByType = clazz.getAnnotationsByType(Bean.class);
            if (annotationsByType.length != 0)
                beanList.add(clazz);
        }

    }

    /**
     * 递归加载类文件
     * @param files
     * @param listFile
     */
    private static void recursiveLoadClassFile(File[] files, List<File> listFile) {

        if (ArrayUtil.isNotEmpty(files)) {
            for (File f : files) {
                if (f.isDirectory()) {
                    recursiveLoadClassFile(f.listFiles(), listFile);
                } else {
                    listFile.add(f);
                }
            }
        }

    }


    public static void main(String[] args) throws Exception {

        System.out.println(Math.min(1, 0));

        String val = null;
        Integer.valueOf(val);

//        loadBeanDefinition();
//
//        System.out.println();

// F:\work\wpml\wpml-servelet-demo\target\classes\com\wpml\po\User.class


        /*File clazzPath = new File("F:\\work\\wpml\\wpml-servelet-demo\\target\\classes");

        Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        boolean accessible = method.isAccessible();
        try {
            if (!accessible) {
                method.setAccessible(true);
            }
            // 设置类加载器
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            // 将当前类路径加入到类加载器中
            method.invoke(classLoader, clazzPath.toURI().toURL());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            method.setAccessible(accessible);
        }
        File subFile = new File("F:\\work\\wpml\\wpml-servelet-demo\\target\\classes\\com\\wpml\\po\\User.class");
        // 文件名称
        int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
        String className = subFile.getAbsolutePath();
        className = className.substring(clazzPathLen, className.length() - 6);
        //将/替换成. 得到全路径类名
        className = className.replace(File.separatorChar, '.');
        // 加载Class类
        Class<?> aClass = Class.forName(className);*/

//        System.out.println(aClass.getName());
    }


    public static void init (String packageName) {

        System.out.println("初始化加载类信息...");

        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            String clazzStr = (String) entry.getValue(); // com.wpml.UserController

            try {
                Class<?> clazz = Class.forName(clazzStr);
                Controller[] annotationsByType = clazz.getAnnotationsByType(Controller.class);
                if (annotationsByType.length > 0) {
                    Method[] declaredMethods = clazz.getDeclaredMethods();
                    for (Method method : declaredMethods) {
                        RequestMapping[] requestMappings = method.getDeclaredAnnotationsByType(RequestMapping.class);
                        if (requestMappings.length > 0) {
                            String uriStr = requestMappings[0].value();

                            Class<?>[] parameterTypes = method.getParameterTypes();

                            beanContainer.put(uriStr, new BeanMateData(clazz, method, parameterTypes));
                        }
                    }
                }


            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }

        /*Reflections ref = new Reflections(packageName);
        Set<Class<?>> clazzSet = ref.getTypesAnnotatedWith(Controller.class);

        for (Class<?> clazz : clazzSet) {
            try {
                Object o = clazz.newInstance();
                Method[] methods = clazz.getDeclaredMethods();

                for (Method method : methods) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
            System.out.println(clazz.getName());
            System.out.println(clazz.getSimpleName());
        }*/
    }

    public static BeanMateData getBeanMateData(String key) {
        return beanContainer.get(key);
    }

    public static List<Class<?>> getBeanList() {
        return beanList;
    }

}
